/*$Id: RemoteTableModel.java 267 2008-04-30 14:42:06Z lrsmith $*/
package com.leetech.gwt.client;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.widgetideas.table.client.TableModel;
import com.leetech.gwt.client.WidgetController.WidgetDTO;

/**
 * A table model whose data source is on a TableModelService servlet.
 * 
 * @author Last modified by $LastChangedBy: lrsmith $.
 * @version $Rev: 267 $ $Date: 2008-04-30 08:42:06 -0600 (Wed, 30 Apr 2008) $.
 */

public class RemoteTableModel extends TableModel {

    // Static initialization-------------------------------------------
    // Instance variables----------------------------------------------
    /**
     * The last request made by a table controller, used to populate additional
     * requests if they incomplete.
     */
    private WidgetDTO[] query;

    /** The remote service used to make requests to fetch data. */
    private TableModelServiceAsync tableServ;

    // Constructors----------------------------------------------------
    /**
     * Constructs a remote table model.
     * 
     * @param tableModelServiceUrl
     *            the url of the table model service servlet.
     */
    public RemoteTableModel(String tableModelServiceUrl) {
        super();
        // open remote service.
        tableServ = (TableModelServiceAsync) GWT
                .create(TableModelService.class);

        ServiceDefTarget endpoint = (ServiceDefTarget) tableServ;
        endpoint.setServiceEntryPoint( tableModelServiceUrl);

        query = null;
    }

    // Methods---------------------------------------------------------
    /**
     * Makes an initial query to populate a table.
     * 
     * @param query
     *            the query to make
     * @param callback
     *            the callback function containing data.
     */
    public void setQuery(WidgetDTO[] query) {
        this.query = query;
    }

    /**
     * Overrides TableModel.requestRows and is used by GWT Incubator code to
     * make basic requests for data.
     */
    public void requestRows(final TableModel.Request req,
            final TableModel.Callback callback) {
        GWT.log("RemoteTableModel: Recieved req for " + req.getNumRows()
                + " rows starting at row " + req.getStartRow() + ".", null);
        
        if (query != null) {
            final Request remoteReq = new Request(req.getStartRow(), req
                    .getNumRows(), req.getColumnSortList());
            remoteReq.setQuery(query);

            GWT.log("RemoteTableModel: Requesting " + remoteReq.getNumRows()
            + " rows starting at row " + remoteReq.getStartRow() + ".", null);

            tableServ.requestRows(remoteReq, new AsyncCallback() {

                public void onFailure(Throwable caught) {
                    caught.printStackTrace();
                    callback.onFailure(caught);
                }

                public void onSuccess(Object obj) {

                    Response resp = (Response) obj;
                    GWT.log("AsyncCallback: Recieved " + resp.getRowCount()
                            + " rows from service.", null);
                    callback.onRowsReady(req, resp);
                }
            });
            // no query -> no results
        } else {
            callback.onRowsReady(new Request(), new Response());
        }
    }

    /*
     * Implement event handlers for mutable tables.
     */
    /**
     * Used for mutable tables. Not implemented.
     */
    public void onRowInserted(int beforeRow) {
    }

    /**
     * Used for mutable tables. Not implemented.
     */
    public void onRowRemoved(int row) {
    }

    /**
     * Used for mutable tables. Not implemented.
     */
    public void onSetData(int firstRow, Collection rows) {
    }

    /**
     * Used for mutable tables. Not implemented.
     */
    public void onSetData(int row, int cell, Object data) {
    }

    // Inner Classes --------------------------------------------------

    /**
     * 
     * 
     * @author Last modified by $LastChangedBy: lrsmith $.
     * @version $Rev: 267 $ $Date: 2008-04-30 08:42:06 -0600 (Wed, 30 Apr 2008) $.
     */
    public static class Request extends TableModel.Request implements
            IsSerializable{

        // Static initialization-------------------------------------------
        // Instance variables----------------------------------------------
        /** The query used to fetch data. */
        private WidgetDTO[] query;
        /** Number of rows requested. */
        private int numRows;
        /** Start row requested. */
        private int startRow;
        /** Contains info about priority sorting order */
        private ColumnSortList columnSortList;

        // Constructors----------------------------------------------------
        /**
         * Default constructor.
         */
        public Request() {
            this(0, 0, null);
        }

        /**
         * Constructor.
         * 
         * @param startRow
         *            the first row to request
         * @param numRows
         *            the number of rows to request
         */
        public Request(int startRow, int numRows) {
            this(startRow, numRows, null);
        }

        /**
         * Constructor.
         * 
         * @param startRow
         *            the first row to request
         * @param numRows
         *            the number of rows to request
         * @param columnSortList
         *            column sort orders
         */
        public Request(int startRow, int numRows, ColumnSortList columnSortList) {
            this.startRow = startRow;
            this.numRows = numRows;
            this.columnSortList = columnSortList;
        }

        // Methods---------------------------------------------------------
        /**
         * Get the {@link ColumnSortInfo}, which includes the sort indexes and
         * ascending or descending order info.
         * 
         * @return the sort info
         */
        public ColumnSortList getColumnSortList() {
            return columnSortList;
        }

        /**
         * Gets the query.
         */
        public WidgetDTO[] getQuery() {
            return query;
        }

        /**
         * Gets the query.
         */
        public void setQuery(WidgetDTO[] query) {
            this.query = query;
        }

        /**
         * Gets the numRows.
         */
        public int getNumRows() {
            return numRows;
        }


        /**
         * Gets the startRow.
         */
        public int getStartRow() {
            return startRow;
        }

    }

    public static class Response extends TableModel.Response implements
            IsSerializable {

        // Static initialization-------------------------------------------

        // Instance variables----------------------------------------------

        /**
         * @gwt.typeArgs <nreldata.nbc.gwt.client.scrolltable.RemoteTableModel.Row>
         */
        private List rows;
        private int columnCount;

        // Constructors----------------------------------------------------
        public Response() {
            rows = new ArrayList();
            this.columnCount = -1;
        }

        public Response(int columnCount) {
            rows = new ArrayList();
            this.columnCount = columnCount;
        }

        // Methods---------------------------------------------------------

        public int getRowCount() {
            return rows.size();
        }

        public int getColumnCount() {
            return columnCount;
        }

        public void add(String[] row, long hiberanteId) {
            rows.add(new Row(row, hiberanteId));
            if (columnCount > -1 && columnCount != row.length) {
                throw (new IndexOutOfBoundsException("Expected column count "
                        + columnCount + " but found " + row.length));
            }
        }

        public Iterator getIterator() {
            return rows.iterator();
        }

        public List getRowValues() {
            return rows;
        }

    }

    public static class Row implements java.util.Iterator, IsSerializable
            {

        private String[] row;
        private Long hibernateId;
        int index;

        public Row() {
            index = 0;
            row = new String[0];
        }

        public Row(String[] row, long hibernateId) {
            this.row = row;
            index = 0;
            this.hibernateId = new Long(hibernateId);
        }

        public boolean hasNext() {
            return (index < row.length - 1);
        }

        /**
         * @gwt.typeArgs <java.lang.String>
         */
        public Object next() {
            return row[index++];
        }

        public void remove() {
            throw new UnsupportedOperationException("Remove not supported.");
        }

        Long getHibernateId() {
            return hibernateId;
        }

    }

}
